package set_;

import java.util.HashSet;

public class HashSetSource {
    public static void main(String[] args) {
        HashSet hashSet = new HashSet();
        hashSet.add("java");
        hashSet.add("php");
        hashSet.add("java");
        System.out.println(hashSet);//[java, php]

        /**
         * 1.调用HashMap的构造器
         * todo
         *      public HashSet() {
         *         map = new HashMap<>();
         *     }
         * 2.调用add方法
         * todo
         *      public boolean add(E e) {//e:"java"
         *         return map.put(e, PRESENT)==null;//PRESENT用来占位
         *         //是hashMap中的一个静态共享常量 private static final Object PRESENT = new Object();
         *         //(1)如果返回值为空说明添加成功
         *         //(2)返回值若为一个查询到的对象，说明添加失败
         *     }
         * 3.执行put方法
         * todo
         *      public V put(K key, V value) {//k:"java" value:
         *         return putVal(hash(key), key, value, false, true);
         *     }
         * 4.进入hash函数  为非空对象计算出一个hash值，key与hash值对应
         * hash值并不等价于hashCode
         * 算法 (h = key.hashCode()) ^ (h >>> 16)按位异或 无符号右移16位（避免冲突）
         * todo
         *      static final int hash(Object key) {
         *         int h;
         *         return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
         *     }
         * 5.hashCode方法
         * todo (String类中）
         *      public int hashCode() {
         *         int h = hash;
         *         if (h == 0 && value.length > 0) {
         *             char val[] = value;
         *             for (int i = 0; i < value.length; i++) {
         *                 h = 31 * h + val[i];
         *             }
         *             hash = h;
         *         }
         *         return h;
         *     }
         * 6.putVal方法
         * todo
         *      @para hash 根据key值计算出来的hash值
         *      @para key  需要存放的key值 key:"java"
         *      @para value  等于HashMap中的共享静态常量 value=PRESENT 用来占位
         *      @para onlyIfAbsent  false
         *      @para evict  true
         *      final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
         *                    boolean evict) {
         *         //临时变量
         *         Node<K,V>[] tab; Node<K,V> p; int n, i;
         *         //transient Node<K,V>[] table;table是HashMap中的一个Node数组
         *         if ((tab = table) == null || (n = tab.length) == 0)
         *             //(1)第一次扩容，调用的是resize方法   第一次扩容为 16 并且有一个加载因子0.75*16=12
         *             //(2)当table已经添加了12个元素就会触发扩容
         *             //(3)最后返回值resize的返回值是一个大小为16的Node数组
         *             //(4)然后赋值给tab
         *             n = (tab = resize()).length;
         *             //(1)根据key计算出来的hash值去计算，此key应该存放在table表的哪个索引位置
         *             //(2)并把这个位置的Node对象赋值给 p(Node类型)
         *             //   (2.1) 如果p=null 说明这个索引位置还没有放过任何元素
         *             //
         *         if ((p = tab[i = (n - 1) & hash]) == null)
         *             tab[i] = newNode(hash, key, value, null);
         *         else {
         *             Node<K,V> e; K k;
         *             if (p.hash == hash &&
         *                 ((k = p.key) == key || (key != null && key.equals(k))))
         *                 e = p;
         *             else if (p instanceof TreeNode)
         *                 e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
         *             else {
         *                 for (int binCount = 0; ; ++binCount) {
         *                     if ((e = p.next) == null) {
         *                         p.next = newNode(hash, key, value, null);
         *                         if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
         *                             treeifyBin(tab, hash);
         *                         break;
         *                     }
         *                     if (e.hash == hash &&
         *                         ((k = e.key) == key || (key != null && key.equals(k))))
         *                         break;
         *                     p = e;
         *                 }
         *             }
         *             if (e != null) { // existing mapping for key
         *                 V oldValue = e.value;
         *                 if (!onlyIfAbsent || oldValue == null)
         *                     e.value = value;
         *                 afterNodeAccess(e);
         *                 return oldValue;
         *             }
         *         }
         *         ++modCount;
         *         //判断此时table的数据量是不是大于扩容临界值
         *         if (++size > threshold)
         *             resize();
         *         //此方法是HashMap中的空方法，用于给给子类实现
         *         afterNodeInsertion(evict);//evict:true传进来的时候是true
         *         return null;
         *     }
         *
         * 7.第二次向hashMap中添加数据
         * todo
         *      final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
         *                    boolean evict) {
         *         Node<K,V>[] tab; Node<K,V> p; int n, i;
         *         //因为在内存中table已经存在故不再进入这个if
         *         if ((tab = table) == null || (n = tab.length) == 0)
         *             n = (tab = resize()).length;
         *         //(1)根据key计算出来的hash值去计算，此key应该存放在table表的哪个索引位置
         *         //(2)并把这个位置的Node对象赋值给 p(Node类型)
         *         //   (2.1) 如果p=null 说明这个索引位置还没有放过任何元素
         *         //   (2.2) 如果不为空，说明这个索引位置有对象了，返回这个对象给 p
         *         if ((p = tab[i = (n - 1) & hash]) == null)
         *             tab[i] = newNode(hash, key, value, null);
         *         else {
         *             Node<K,V> e; K k;
         *             //当前位置的对象 p 和准备新添加进来的对象的hash值相同
         *             //&&并且
         *             //  (1) 当前位置的对象 p 和准备新添加进来的对象是同一个对象 == 比较的是地址
         *             //  (2) 当前位置的对象 p 和准备新添加进来的对象的值是一样的 equals比较的是值
         *             //  先比较hash值，再比较是不是同一个对象，或者两个对象的值是否相等
         *             //  因此其实思考一下可以发现不同的对象的hash值可能也会相同
         *             //  而equals()常用于给程序员重写用来按不同的标准确定两个对象的等价关系
         *             //  这也是为什么之前我们两次执行hashset.add(new String("lixu"))最终只添加了一次，这是因为String重写了equals
         *             if (p.hash == hash &&
         *                 ((k = p.key) == key || (key != null && key.equals(k))))
         *                 e = p;
         *              // 红黑树
         *             else if (p instanceof TreeNode)
         *                 e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
         *             else {
         *             //  如果table对应的索引位置已经是一个链表，就for循环遍历每个节点
         *             //  (1)与每个节点对象比较都不同，则将此节点加入到链表尾部,break;
         *             //  (2)如果hash值相同，再比较是不是同一个对象，或者两个对象的值是否相等，就不添加，break;
         *             //注意：
         *             //   - TREEIFY_THRESHOLD(8) 当前索引位置构成的链表长度已经达到8个就需要树化treeifyBin(tab, hash);
         *             //   - treeifyBin方法树化前会判断if (tab == null || (n = tab.length) < MIN_TREEIFY_CAPACITY)
         *                                                             resize();
         *             //   MIN_TREEIFY_CAPACITY(64) table数组的容量是否已经大于64了，大于64才会树化，否则就扩容resize();
         *             //   所以并不是满足 链表长度已经达到8个就立马树化（并不是第九个）
         *                 for (int binCount = 0; ; ++binCount) {
         *                     if ((e = p.next) == null) {
         *                         p.next = newNode(hash, key, value, null);
         *                         if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
         *                             treeifyBin(tab, hash);
         *                         break;
         *                     }
         *                     if (e.hash == hash &&
         *                         ((k = e.key) == key || (key != null && key.equals(k))))
         *                         break;
         *                     p = e;
         *                 }
         *             }
         *             if (e != null) { // existing mapping for key
         *                 V oldValue = e.value;
         *                 if (!onlyIfAbsent || oldValue == null)
         *                     e.value = value;
         *                 afterNodeAccess(e);
         *                 return oldValue;
         *             }
         *         }
         *         ++modCount;
         *         if (++size > threshold)
         *             resize();
         *         afterNodeInsertion(evict);
         *         return null;
         *     }
         */
    }
}
